package com.bj58.mis.apm.collector.http;

import com.bj58.mis.apm.client.core.util.MapUtil;
import com.bj58.mis.apm.collector.BaseSchedulableCollector;

import java.io.Serializable;
import java.util.*;

/**
 * @author: zhangfx
 * @create: 2018-06-12 14:41
 **/
public class HttpAccessStatisticCollector extends BaseSchedulableCollector<HttpAccessStatistic> {

    private int timePeriod = 60*1000;

    /**
     * {
     *     time : {
     *         path: {
     *             method_status: HttpAccessStatistic
     *         }
     *     }
     * }
     */
    private Map<Long, Map<String, Map<String, HttpAccessStatistic>>> statisticMap = new HashMap<>();;

    private synchronized void addRecord(HttpAccessStatistic record){
        long time = record.getRequestTime() / timePeriod * timePeriod;
        Map<String, Map<String, HttpAccessStatistic>> timeMap= statisticMap.get(time);
        if (timeMap == null){
            timeMap = new HashMap<>();
            statisticMap.put(time, timeMap);
        }

        String path = record.getRequestPath();
        Map<String, HttpAccessStatistic> pathMap = timeMap.get(path);
        if(pathMap == null){
            pathMap = new HashMap<>();
            timeMap.put(path, pathMap);
        }

        String methodStatus = record.getRequestMethod()+"_"+record.getResponseStatus();
        HttpAccessStatistic statistic = pathMap.get(methodStatus);
        if(statistic == null){
            statistic = record;
            statistic.setRequestTime(time);
            pathMap.put(methodStatus, statistic);
        }else {
            statistic.setRequestCount( statistic.getRequestCount() + record.getRequestCount());
            statistic.setTotalTimeTaken( statistic.getTotalTimeTaken() + record.getTotalTimeTaken());
            statistic.setMaxTimeTaken(Math.max(statistic.getMaxTimeTaken(), record.getMaxTimeTaken()));
            statistic.setMinTimeTaken(Math.min(statistic.getMinTimeTaken(), record.getMinTimeTaken()));
            statistic.setAvgTimeTaken(statistic.getTotalTimeTaken()/statistic.getRequestCount());
        }
        //System.out.println(MapUtil.mapToPrintString(statisticMap, ""));
    }


    private synchronized List<HttpAccessStatistic> getAndClearStatisticMap(){
        List<HttpAccessStatistic> list = new LinkedList<>();
        for (Map.Entry<Long, Map<String, Map<String, HttpAccessStatistic>>> timeEntry : statisticMap.entrySet()){
            for(Map.Entry<String, Map<String, HttpAccessStatistic>> pathEntry : timeEntry.getValue().entrySet() ){
                for (Map.Entry<String, HttpAccessStatistic> entry : pathEntry.getValue().entrySet()){
                    list.add(entry.getValue());
                }
            }
        }
        statisticMap = new HashMap<>();;
        return list;
    }

    @Override
    protected void collectHandle(HttpAccessStatistic statisticRecord) {
        if(statisticRecord.isStatistic()){
            super.collectHandle(statisticRecord);
        }else{
            addRecord(statisticRecord);
        }
    }

    @Override
    public void schedule() {
        List<HttpAccessStatistic> statisticList = getAndClearStatisticMap();
        for(HttpAccessStatistic statistic : statisticList){
            statistic.setStatistic(true);
            collect(statistic);
        }
    }
}

